// arch/riscv/kernel/proc.c
#include "proc.h"
#include "defs.h"
#include "mm.h"
#include "rand.h"
#include "printk.h"
#include "math.h"

extern void __dummy();

struct task_struct* idle;           // idle process
struct task_struct* current;        // 指向当前运行线程的 `task_struct`
struct task_struct* task[NR_TASKS]; // 线程数组，所有的线程都保存在此

void task_init() {
    idle = (struct task_struct*)kalloc();
    idle->state = TASK_RUNNING;
    idle->counter = 0;
    idle->priority = 0;
    idle->pid = 0;
    current = idle;
    task[0] = idle;

    for(int i = 1;i < NR_TASKS;i ++){
        task[i] = (struct task_struct*)kalloc();
        task[i]->state = TASK_RUNNING;
        task[i]->counter = 0;
        task[i]->priority = int_mod(rand(),PRIORITY_MAX - PRIORITY_MIN + 1) + PRIORITY_MIN;
        task[i]->pid = i;
        task[i]->thread.ra = (uint64)__dummy;
        task[i]->thread.sp = (uint64)task[i] + PGSIZE;
    }
  
    printk("proc_init\n");
}

void dummy() {
    uint64 MOD = 1000000007;
    uint64 auto_inc_local_var = 0;
    int last_counter = -1; // 记录上一个counter
    int last_last_counter = -1; // 记录上上个counter
    while(1) {
        if (last_counter == -1 || current->counter != last_counter) {
            last_last_counter = last_counter;
            last_counter = current->counter;
            auto_inc_local_var = int_mod(auto_inc_local_var + 1,MOD);
            printk("[PID = %d]. auto_inc_local_var = %d\n", current->pid, auto_inc_local_var);
        } else if((last_last_counter == 0 || last_last_counter == -1) && last_counter == 1) { // counter恒为1的情况
            // 这里比较 tricky，不要求理解。
            last_counter = 0;
            current->counter = 0;
        }
    }
}

extern void __switch_to(struct task_struct* prev, struct task_struct* next);

void switch_to(struct task_struct* next) {
    if(next != current){
        printk("switch to [PID %d, PRIO %d, CNT %d]\n", next->pid, next->priority, next->counter);
        struct task_struct* prev = current;
        current = next;
        __switch_to(prev,next);
    }
}

void do_timer(void) {
    if(current->counter == 0) schedule();
    else if(--current->counter == 0) schedule(); 
}

void schedule(void) {
    // int i,min_counter;
    struct task_struct* next;
    // printk("SHEDULE!\n");
	while (1) {
		int min_counter = PRIORITY_MAX+1;
		for(int i = 1;i < NR_TASKS;i ++){
            // printk("i = %d, task[%d]->counter = %d \n",i,task[i]->pid,task[i]->counter);
            if(task[i]->state == TASK_RUNNING  && task[i]->counter != 0 && (int)task[i]->counter < min_counter){
                min_counter = task[i]->counter, next = task[i];
                // printk("maxcounter = %d\n",max_counter);
            }
        }
		if (min_counter != PRIORITY_MAX+1){
            // printk("out!\n");
            break;
        }
		for(int i = 1;i < NR_TASKS;i ++){
            if (task[i]){
                task[i]->counter = (task[i]->counter >> 1) + task[i]->priority;
                printk("SET [PID = %d, PRIORITY = %d, COUNTER = %d]\n",task[i]->pid,task[i]->priority,task[i]->counter);
            }
        }
	}
	switch_to(next);
}
